<?php

/**
 * Class RoleService
 */
class RoleService extends Model
{
    private $_customerId = null;    // cid
    private $_logicRole = null;     // 角色
    private $_logicRoleModuleGroup = null;  // 角色和模块
    private $_logicRoleAction = null;       // 角色和功能
    private $_logicCustomerUserRole = null; // 用户和角色

    private $_serviceModule = null; // 模块的service

    public function __construct()
    {
        $this->_customerId = Session::$user['customerId'];
        $this->_logicRole = D('Role', 'Logic');
        $this->_logicRoleModuleGroup = D('RoleModuleGroup', 'Logic');
        $this->_logicRoleAction = D('RoleAction', 'Logic');
        $this->_logicCustomerUserRole = D('CustomerUserRole', 'Logic');

        $this->_serviceModule = D('Module', 'Service');
    }

    /**
     * 增加一个角色
     *
     * @param $englishRole
     * @param $chineseRole
     * @param $manual
     * @return array
     */
    public function addRole($englishRole, $chineseRole, $manual)
    {
        // 组织增加的数据
        $data = [
            'cid'   => $this->_customerId,
            'englishRole'   => $englishRole,
            'chineseRole'   => $chineseRole,
            'manual'        => $manual,
            'isSys' => 0,
            'auage' => ''
        ];

        // 增加角色
        $roleId = $this->_logicRole->addRole($data);

        // 返回
        if (is_numeric($roleId)) {
            $Out = [
                'code'  => 0,
                'msg'   => '创建角色成功',
                'data'  => [
                    'roleId'    => $roleId
                ]
            ];
        } else {
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误',
                'data'  => []
            ];
        }
        return $Out;
    }

    /**
     * 删除一个自定义的角色
     *
     * @param $roleId
     *
     * @return mixed
     */
    public function delRoleById($roleId)
    {
        // 判断角色是否可删除
        $res_isSys = $this->_logicRole->getFieldById($roleId, 'isSys');
        if ($res_isSys['isSys']) {   // 如果$isSys为1, 则为系统角色, 不可删除
            $Out = [
                'code'  => 1,
                'msg'   => '该角色为系统角色, 不可删除',
                'data'  => []
            ];
            return $Out;
        }

        M()->startTrans();
        // 删除角色
        $res_role = $this->_logicRole->deleteById($roleId);
        if (!is_numeric($res_role)) {
            M()->rollback();
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误',
                'data'  => []
            ];
            return $Out;
        }
        // 删除角色关联的module
        $res_roleModuleGroup = $this->_logicRoleModuleGroup->deleteByRoleId($roleId);
        if (!is_numeric($res_roleModuleGroup)) {
            M()->rollback();
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误',
                'data'  => []
            ];
            return $Out;
        }
        // 删除角色授予的人
        $res_customerUserRole = $this->_logicCustomerUserRole->deleteByRoleId($roleId);
        if (!is_numeric($res_customerUserRole)) {
            M()->rollback();
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误',
                'data'  => []
            ];
            return $Out;
        }
        // 删除角色关联的action

        M()->commit();

        $Out = [
            'code'  => 0,
            'msg'   => '',
            'data'  => [
                'res_role'  => $res_role,
                'res_roleModuleGroup'   => $res_roleModuleGroup,
                'res_customerUserRole'  => $res_customerUserRole
            ]
        ];
        return $Out;
    }

    /**
     * 更新角色对应模块
     * 删除db库里废弃的角色对应的模块, 新增角色对应的模块
     *
     * @param       $roleId
     * @param array $groupIds
     * @return array|void
     */
    public function updateRoleGroup($roleId, $groupIds = [])
    {
        $dbGroupIds = $this->getGroupIdsByRoleId($roleId);
        $addGroupIds = array_values(array_diff($groupIds, $dbGroupIds));    // 新增原数据库中没有的groupId数组
        $delGroupIds = array_values(array_diff($dbGroupIds, $groupIds));    // 删除数据库中原有被更新删除的groupId数组

        M()->startTrans();
        if (!empty($delGroupIds)) {
            $delWhere = ['cid' => $this->_customerId, 'agent' => $roleId, 'groupId' => ['IN', $delGroupIds]];
            $res_del = $this->_logicRoleModuleGroup->deleteWithWhere($delWhere);
            if (!is_numeric($res_del)) {
                M()->rollback();
                $Out = [
                    'code'  => 505,
                    'msg'   => '数据读写错误 - 删除角色对应模块错误',
                    'data'  => []
                ];
                return $Out;
            }
        }

        if (!empty($addGroupIds)) {
            // 处理新增
            $addData = [];
            foreach ($addGroupIds as $k_a => $v_a) {
                $add = ['cid' => $this->_customerId, 'groupId' => $v_a, 'agent' => $roleId];

                array_push($addData, $add);
            }
            $res_add = $this->_logicRoleModuleGroup->addAll($addData);
            if (!is_numeric($res_add)) {
            \Log::write('$addData = ' . json_encode($addData));
            \Log::write('$this->_logicRoleModuleGroup sql = ' . $this->_logicRoleModuleGroup->getLastSql());
            M()->rollback();
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误 - 新增角色对应模块错误',
                'data'  => []
            ];
            return $Out;
        }
        }

        M()->commit();
        $roleName = $this->_logicRole->getFieldById($roleId, 'chineseRole');
        $roleName = implode(',', $roleName);
        R('Log/add',array('permission','','权限角色',op_update,'','修改角色：' . $roleName . '的权限'));
        $Out = [
            'code'  => 0,
            'msg'   => '更新角色对应模块成功',
            'data'  => [
                'res_delModuleGroup'   => !empty($res_del) ? $res_del : [],
                'res_addModuleGroup'   => !empty($res_add) ? $res_add : []
            ]
        ];
        return $Out;
    }

    /**
     * 更新角色对应模块功能
     * 删除db库里废弃的角色对应的模块功能, 新增角色对应的模块功能
     *
     * @param       $roleId
     * @param array $actionIds
     * @return array|void
     */
    public function updateRoleAction($roleId, $actionIds = [])
    {
        $dbActionIds = $this->getActionIdsByRoleId($roleId);
        $addActionIds = array_values(array_diff($actionIds, $dbActionIds));    // 新增原数据库中没有的actionId数组
        $delActionIds = array_values(array_diff($dbActionIds, $actionIds));    // 删除数据库中原有被更新删除的actionId数组

        M()->startTrans();
        if (!empty($delActionIds)) {
            $delWhere = ['cid' => $this->_customerId, 'roleId' => $roleId, 'actionId' => ['IN', $delActionIds]];
            $res_del = $this->_logicRoleAction->deleteWithWhere($delWhere);
            if (!is_numeric($res_del)) {
                M()->rollback();
                $Out = [
                    'code'  => 505,
                    'msg'   => '数据读写错误 - 删除角色对应action失败',
                    'data'  => []
                ];
                return $Out;
            }
        }

        if (!empty($addActionIds)) {
            // 处理新增
            $addData = [];
            foreach ($addActionIds as $k_a => $v_a) {
                $add = ['cid' => $this->_customerId, 'actionId' => $v_a, 'roleId' => $roleId];

                array_push($addData, $add);
            }
            $res_add = $this->_logicRoleAction->addAll($addData);
            if (!is_numeric($res_add)) {
                M()->rollback();
                $Out = [
                    'code'  => 505,
                    'msg'   => '数据读写错误 - 新增角色对应action失败',
                    'data'  => []
                ];
                return $Out;
            }
        }

        M()->commit();
        $Out = [
            'code'  => 0,
            'msg'   => '更新角色对应模块成功',
            'data'  => [
                'res_delAction'   => !empty($res_del) ? $res_del : 0,
                'res_addAction'   => !empty($res_add) ? $res_add : 0
            ]
        ];
        return $Out;
    }

    /**
     * 查询角色列表
     *
     * @param string $keyword   关键字查询
     * @param string $order
     * @param string $orderBy
     * @param int    $start
     * @param int    $limit
     * @return array
     */
    public function getRoles($keyword = '', $order = 'id', $orderBy = 'desc', $start = 0, $limit = 10)
    {
        $fields = 'id, chineseRole, isSys'; // 查询字段

        // 查询条件
        $where['cid'] = $this->_customerId;
        if (!empty($keyword)) {
            $where['chineseRole'] = ['LIKE', '%' . $keyword . '%'];
        }
//        $where['manual'] = 1;

        // 查询
        M()->startTrans();
        $data = $this->_logicRole->selectPage($fields, $where, $order, $orderBy, $start, $limit);
        if ($data === FALSE) {
            M()->rollback();
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误',
                'data'  => []
            ];
            return $Out;
        }
        $count = $this->_logicRole->selectPageCount($where);
        if ($data === FALSE) {
            M()->rollback();
            $Out = [
                'code'  => 505,
                'msg'   => '数据读写错误',
                'data'  => []
            ];
            return $Out;
        }

        M()->commit();
        // 返回
        $Out = [
            'code'  => 0,
            'msg'   => '查询角色列表数据成功',
            'data'  => [
                'count' => $count,
                'data'  => $data
            ]
        ];
        return $Out;
    }

    /**
     * 根据角色id查询该角色当前模块和功能点的配置情况 - 是否选中都显示
     *
     * @param $roleId
     * @return mixed
     */
    public function getRoleById($roleId)
    {
        $modules = $this->_serviceModule->getModules(); // 获得模块列表
        $modules = $modules['data']['modules'];

        $roleModules = $this->getGroupIdsByRoleId($roleId);
        $roleActions = $this->getActionIdsByRoleId($roleId);

        foreach ($modules as $k_module => $v_module) {
            if (empty($v_module['children'])) { // 该一级模块没有子模块
                // 处理该模块是否在该角色被选中
                if (in_array($v_module['id'], $roleModules)) {
                    $modules[$k_module]['isSelect'] = 1;
                } else {
                    $modules[$k_module]['isSelect'] = 0;
                }

                // 处理该模块的功能点状态在该角色下的选中状态
                foreach ($v_module['actions'] as $k_action => $v_action) {
                    if (in_array($v_action['id'], $roleActions)) {
                        $modules[$k_module]['actions'][$k_action]['isSelect'] = 1;
                    } else {
                        $modules[$k_module]['actions'][$k_action]['isSelect'] = 0;
                    }
                }
            } else {    // 处理子级模块
                foreach ($v_module['children'] as $k_children => $v_children) {
                    // 处理该模块是否在该角色被选中
                    if (in_array($v_children['id'], $roleModules)) {
                        $modules[$k_module]['children'][$k_children]['isSelect'] = 1;
                    } else {
                        $modules[$k_module]['children'][$k_children]['isSelect'] = 0;
                    }

                    // 处理该模块的功能点状态在该角色下的选中状态
                    foreach ($v_children['actions'] as $k_action => $v_action) {
                        if (in_array($v_action['id'], $roleActions)) {
                            $modules[$k_module]['children'][$k_children]['actions'][$k_action]['isSelect'] = 1;
                        } else {
                            $modules[$k_module]['children'][$k_children]['actions'][$k_action]['isSelect'] = 0;
                        }
                    }
                }
            }
        }

        $Out = [
            'code'  => 0,
            'msg'   => '查询角色配置数据成功',
            'data'  => [
                'roleModules'  => $modules
            ]
        ];
        return $Out;
    }

    /**
     * 根据角色id显示该角色当前模块和功能点的配置情况 - 只显示选中的
     *
     * @param $roleId
     * @return array
     */
    public function showRoleById($roleId)
    {
        $modules = $this->_serviceModule->getModules(); // 获得模块列表
        $modules = $modules['data']['modules'];

        $roleModules = $this->getGroupIdsByRoleId($roleId);
        $roleActions = $this->getActionIdsByRoleId($roleId);

        foreach ($modules as $k_module => $v_module) {
            if (empty($v_module['children'])) { // 该一级模块没有子模块
                // 处理该模块是否在该角色被选中
                if (!in_array($v_module['id'], $roleModules)) {
                    unset($modules[$k_module]);
                    continue;
                }

                // 处理该模块的功能点状态在该角色下的选中状态
                foreach ($v_module['actions'] as $k_action => $v_action) {
                    if (!in_array($v_action['id'], $roleActions)) {
                        unset($modules[$k_module]['actions'][$k_action]);
                        continue;
                    }
                }
            } else {    // 处理子级模块
                if ($v_module['id'] == 121) {
                    \Log::write('start');
                }
                foreach ($v_module['children'] as $k_children => $v_children) {
                    // 处理该模块是否在该角色被选中
                    if (!in_array($v_children['id'], $roleModules)) {
                        unset($modules[$k_module]['children'][$k_children]);
                        continue;
                    }

                    // 处理该模块的功能点状态在该角色下的选中状态
                    foreach ($v_children['actions'] as $k_action => $v_action) {
                        if (!in_array($v_action['id'], $roleActions)) {
                            unset($modules[$k_module]['children'][$k_children]['actions'][$k_action]);
                            continue;
                        }
                    }
                }

                // 二级模块都没有, 去掉一级模块
                if (empty($modules[$k_module]['children'])) {
                    unset($modules[$k_module]);
                    continue;
                }
            }
        }

        $modules = array_values($modules);  // 去掉数字key

        $Out = [
            'code'  => 0,
            'msg'   => '显示角色配置数据成功',
            'data'  => [
                'roleModules'  => $modules
            ]
        ];
        return $Out;
    }

    /** ****************************************  私有方法  **************************************** */

    /**
     * 根据roleId获得角色对应的groupId数组
     *
     * @param $roleId
     * @return mixed
     */
    private function getGroupIdsByRoleId($roleId)
    {
        // 查询这个role下的groupId列表
        $where['agent'] = $roleId;

        $arr_groupIds = $this->_logicRoleModuleGroup->getField($where, 'groupId', TRUE);
        $arr_groupIds = !empty($arr_groupIds) ? $arr_groupIds : [];

        return $arr_groupIds;
    }

    /**
     * 根据roleId获得角色对应的actionId数组
     *
     * @param $roleId
     * @return mixed
     */
    private function getActionIdsByRoleId($roleId)
    {
        // 查询这个role下的actionId列表
        $where['roleId'] = $roleId;

        $arr_actionIds = $this->_logicRoleAction->getField($where, 'actionId', TRUE);
        $arr_actionIds = !empty($arr_actionIds) ? $arr_actionIds : [];

        return $arr_actionIds;
    }

}